﻿namespace Example.Security.Cryptography
{
    using System;
    using System.IO;
    using System.Text;

    using Xunit;

    public class Md5DigestUnitFacts
    {
        private const string EmptyHash = "1B2M2Y8AsgTpgAmY7PhCfg==";

        private const string JigsawHash = "0TMnkhCZtrIjdTtJk6x3+Q==";

        /// <summary>
        /// http://jigsaw.w3.org/HTTP/h-content-md5.html
        /// </summary>
        private const string JigsawHtml = "<HTML>\n"
                                          + "<HEAD>\n  <!-- Created with 'cat' and 'vi'  -->\n"
                                          + "<TITLE>Retry-After header</TITLE>\n"
                                          + "</HEAD>\n"
                                          + "<BODY>\n"
                                          + "<P>\n"
                                          + "<A HREF=\"..\"><IMG SRC=\"/icons/jigsaw\" ALT=\"Jigsaw\" BORDER=\"0\" WIDTH=\"212\"\n    HEIGHT=\"49\"></A>\n"
                                          + "<H1>\nThe <I>Content-MD5</I> header\n</H1>\n"
                                          + "<P>This pages is served along with its MD5 digest, you take\na look at the headers, as it is quite difficult to do an auto-referent\npage about its md5 signature :)\n"
                                          + "</P>\n  <HR>\n<BR>\n"
                                          + "<A HREF=\"mailto:jigsaw@w3.org\">jigsaw@w3.org</A>\n"
                                          + "</BODY></HTML>\n \n";

        [Fact]
        public void op_Calculate_FileSystemInfo()
        {
            const string expected = JigsawHash;
            var actual = Md5Digest.Calculate(new FileInfo("jigsaw.html"));

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_FileSystemInfoEmpty()
        {
            const string expected = EmptyHash;
            var actual = Md5Digest.Calculate(new FileInfo("empty.html"));

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_FileSystemInfoNull()
        {
            Assert.Throws<ArgumentNullException>(() => Md5Digest.Calculate(null as FileSystemInfo));
        }

        [Fact]
        public void op_Calculate_Uri()
        {
            const string expected = JigsawHash;
            var actual = Md5Digest.Calculate(new Uri("http://jigsaw.w3.org/HTTP/h-content-md5.html"));

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_UriNull()
        {
            Assert.Throws<ArgumentNullException>(() => Md5Digest.Calculate(null as Uri));
        }

        [Fact]
        public void op_Calculate_byte()
        {
            const string expected = JigsawHash;
            var actual = Md5Digest.Calculate(Encoding.Default.GetBytes(JigsawHtml));

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_byteEmpty()
        {
            const string expected = EmptyHash;
            var actual = Md5Digest.Calculate(new byte[]
                                                 {
                                                 });

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_byteNull()
        {
            Assert.Throws<ArgumentNullException>(() => Md5Digest.Calculate(null as byte[]));
        }

        [Fact]
        public void op_Calculate_stream()
        {
            const string expected = JigsawHash;
            string actual;

            using (var stream = new MemoryStream())
            {
                using (var writer = new StreamWriter(stream))
                {
                    writer.Write(JigsawHtml);
                    writer.Flush();
                    stream.Position = 0;

                    actual = Md5Digest.Calculate(stream);
                }
            }

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_streamEmpty()
        {
            const string expected = EmptyHash;
            string actual;

            using (var stream = new MemoryStream())
            {
                actual = Md5Digest.Calculate(stream);
            }

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_streamNull()
        {
            Assert.Throws<ArgumentNullException>(() => Md5Digest.Calculate(null as Stream));
        }

        [Fact]
        public void op_Calculate_string()
        {
            const string expected = JigsawHash;
            var actual = Md5Digest.Calculate(JigsawHtml);

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_stringEmpty()
        {
            const string expected = EmptyHash;
            var actual = Md5Digest.Calculate(string.Empty);

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_stringEmpty_Encoding()
        {
            const string expected = EmptyHash;
            var actual = Md5Digest.Calculate(string.Empty, Encoding.Default);

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_stringNull()
        {
            Assert.Throws<ArgumentNullException>(() => Md5Digest.Calculate(null as string));
        }

        [Fact]
        public void op_Calculate_stringNull_Encoding()
        {
            Assert.Throws<ArgumentNullException>(() => Md5Digest.Calculate(null, Encoding.Default));
        }

        [Fact]
        public void op_Calculate_string_Encoding()
        {
            const string expected = JigsawHash;
            var actual = Md5Digest.Calculate(JigsawHtml, Encoding.Default);

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void op_Calculate_string_EncodingNull()
        {
            Assert.Throws<ArgumentNullException>(() => Md5Digest.Calculate("test", null));
        }
    }
}